﻿using laohan.Common.USB.DeviceNotify;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace laohan.Common.USB
{
    public class Win32API
    {
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct Overlapped
        {
            public uint Internal;

            public uint InternalHigh;

            public uint Offset;

            public uint OffsetHigh;

            public IntPtr Event;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct DeviceInterfaceData
        {
            public int Size;

            public Guid InterfaceClassGuid;

            public int Flags;

            public IntPtr Reserved;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct HidCaps
        {
            public ushort Usage;

            public ushort UsagePage;

            public ushort InputReportByteLength;

            public ushort OutputReportByteLength;

            public ushort FeatureReportByteLength;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
            public ushort[] Reserved;

            public ushort NumberLinkCollectionNodes;

            public ushort NumberInputButtonCaps;

            public ushort NumberInputValueCaps;

            public ushort NumberInputDataIndices;

            public ushort NumberOutputButtonCaps;

            public ushort NumberOutputValueCaps;

            public ushort NumberOutputDataIndices;

            public ushort NumberFeatureButtonCaps;

            public ushort NumberFeatureValueCaps;

            public ushort NumberFeatureDataIndices;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct DeviceInterfaceDetailData
        {
            public int Size;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string DevicePath;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
        internal class DeviceBroadcastInterface
        {
            public int Size;

            public int DeviceType;

            public IntPtr Reserved;

            public Guid ClassGuid;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string Name;
        }

        [Serializable]
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        [BestFitMapping(false)]
        public struct WIN32_FIND_DATA
        {
            public IntPtr dwFileAttributes;

            public int ftCreationTime_dwLowDateTime;

            public int ftCreationTime_dwHighDateTime;

            public int ftLastAccessTime_dwLowDateTime;

            public int ftLastAccessTime_dwHighDateTime;

            public int ftLastWriteTime_dwLowDateTime;

            public int ftLastWriteTime_dwHighDateTime;

            public int nFileSizeHigh;

            public int nFileSizeLow;

            public IntPtr dwReserved0;

            public IntPtr dwReserved1;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string cFileName;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
            public string cAlternateFileName;
        }

        internal const int WM_DEVICECHANGE = 537;

        internal const int DEVICE_ARRIVAL = 32768;

        internal const int DEVICE_REMOVECOMPLETE = 32772;

        internal const int DIGCF_PRESENT = 2;

        internal const int DIGCF_DEVICEINTERFACE = 16;

        internal const int DEVTYP_DEVICEINTERFACE = 5;

        internal const int DEVICE_NOTIFY_WINDOW_HANDLE = 0;

        internal const uint PURGE_TXABORT = 1u;

        internal const uint PURGE_RXABORT = 2u;

        internal const uint PURGE_TXCLEAR = 4u;

        internal const uint PURGE_RXCLEAR = 8u;

        internal const uint GENERIC_READ = 2147483648u;

        internal const uint GENERIC_WRITE = 1073741824u;

        internal const uint FILE_SHARE_WRITE = 2u;

        internal const uint FILE_SHARE_READ = 1u;

        internal const uint FILE_FLAG_OVERLAPPED = 1073741824u;

        internal const uint CREATE_NEW = 1u;

        internal const uint CREATE_ALWAYS = 2u;

        internal const uint OPEN_EXISTING = 3u;

        internal const uint OPEN_ALWAYS = 4u;

        internal const uint ERROR_IO_PENDING = 997u;

        internal const uint INFINITE = uint.MaxValue;

        public static Guid HIDGuid
        {
            get
            {
                HidD_GetHidGuid(out var gHid);
                return gHid;
            }
        }

        [DllImport("hid.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern void HidD_GetHidGuid(out Guid gHid);

        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern IntPtr SetupDiGetClassDevs(ref Guid gClass, [MarshalAs(UnmanagedType.LPStr)] string strEnumerator, IntPtr hParent, uint nFlags);

        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern int SetupDiDestroyDeviceInfoList(IntPtr lpInfoSet);

        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern bool SetupDiEnumDeviceInterfaces(IntPtr lpDeviceInfoSet, uint nDeviceInfoData, ref Guid gClass, uint nIndex, ref DeviceInterfaceData oInterfaceData);

        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr lpDeviceInfoSet, ref DeviceInterfaceData oInterfaceData, IntPtr lpDeviceInterfaceDetailData, uint nDeviceInterfaceDetailDataSize, ref uint nRequiredSize, IntPtr lpDeviceInfoData);

        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr lpDeviceInfoSet, ref DeviceInterfaceData oInterfaceData, ref DeviceInterfaceDetailData oDetailData, uint nDeviceInterfaceDetailDataSize, ref uint nRequiredSize, IntPtr lpDeviceInfoData);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern bool UnregisterDeviceNotification(IntPtr hHandle);

        [DllImport("user32.dll", CharSet = CharSet.Ansi, EntryPoint = "RegisterDeviceNotificationA", SetLastError = true)]
        internal static extern SafeNotifyHandle RegisterDeviceNotification(IntPtr hRecipient, [In][MarshalAs(UnmanagedType.AsAny)] object notificationFilter, int flags);

        [DllImport("hid.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern bool HidD_GetPreparsedData(IntPtr hFile, out IntPtr lpData);

        [DllImport("hid.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern bool HidD_FreePreparsedData(ref IntPtr pData);

        [DllImport("hid.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern int HidP_GetCaps(IntPtr lpData, out HidCaps oCaps);

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern IntPtr CreateFile([MarshalAs(UnmanagedType.LPStr)] string strName, uint nAccess, uint nShareMode, IntPtr lpSecurity, uint nCreationFlags, uint nAttributes, IntPtr lpTemplate);

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        internal static extern int CloseHandle(IntPtr hFile);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr FindFirstFile(string pFileName, ref WIN32_FIND_DATA pFindFileData);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool FindNextFile(IntPtr hndFindFile, ref WIN32_FIND_DATA lpFindFileData);

        public static bool UnregisterForUsbEvents(IntPtr hHandle)
        {
            return UnregisterDeviceNotification(hHandle);
        }
    }
}
